package com.wr.hangzhounewlight.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wr.hangzhounewlight.mapper.OrderMapper;
import com.wr.hangzhounewlight.mapper.RecipeMapper;
import com.wr.hangzhounewlight.mapper.SiloRawMaterialMapMapper;
import com.wr.hangzhounewlight.obj.api.orderclosed.OrderClosedRequest;
import com.wr.hangzhounewlight.obj.api.orderclosed.OrderClosedResponse;
import com.wr.hangzhounewlight.obj.api.orderclosed.OrderClosedResponse.OrderSetDTO;
import com.wr.hangzhounewlight.obj.api.orderclosed.OrderClosedResponse.OrderSetDTO.SiloSetDTO;
import com.wr.hangzhounewlight.obj.database.OrderEntity;
import com.wr.hangzhounewlight.obj.dto.SelectSiloByOrderNoDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
 * @author yuanzhizhuo
 * createDate 2025/10/23
 */
@Slf4j
@Service
public class OrderClosedService {

    private final OrderMapper orderMapper;
    private final RecipeMapper recipeMapper;
    private final SiloRawMaterialMapMapper siloRawMaterialMapMapper;

    public OrderClosedService(
            OrderMapper orderMapper, RecipeMapper recipeMapper, SiloRawMaterialMapMapper siloRawMaterialMapMapper
    ) {
        this.orderMapper = orderMapper;
        this.recipeMapper = recipeMapper;
        this.siloRawMaterialMapMapper = siloRawMaterialMapMapper;
    }

    /**
     * 组合订单关闭
     *
     * @param request dto
     * @return 是否关闭成功
     */
    public OrderClosedResponse orderClosed(OrderClosedRequest request) {
        CheckOrderNoIsExistRecord checkOrderNoIsExistRecord = checkOrderNoIsExist(request.getOrderSet());
        if (!checkOrderNoIsExistRecord.allIsExist()) {
            List<String> inputOrderNoList = new ArrayList<>(checkOrderNoIsExistRecord.inputOrderNoList());
            List<String> databaseOrderNoList = new ArrayList<>(checkOrderNoIsExistRecord.databaseOrderNoList());
            inputOrderNoList.removeAll(databaseOrderNoList);
            return new OrderClosedResponse(0, "组合单号: " + inputOrderNoList + "不存在：", null);
        }
        CheckOrderNoSiloIsExistRecord checkOrderNoSiloIsExistRecord = checkOrderNoSiloIsExist(request.getOrderSet());
        if (!checkOrderNoSiloIsExistRecord.allIsExist()) {
            List<String> recipeTableSiloList = new ArrayList<>(checkOrderNoSiloIsExistRecord.recipeTableSiloList());
            List<String> mapTableSiloList = new ArrayList<>(checkOrderNoSiloIsExistRecord.mapTableSiloList());
            recipeTableSiloList.removeAll(mapTableSiloList);
            return new OrderClosedResponse(0, "组合单号: " + checkOrderNoSiloIsExistRecord.orderNo() + "的料仓: " + recipeTableSiloList + "没有下发到对照表", null);
        }
        List<OrderSetDTO> orderSetDTOList = buildOrderNoRecipe(checkOrderNoSiloIsExistRecord.selectSiloByOrderNoDTOList());
        updateOrderNoIsClose(request.getOrderSet());
        return new OrderClosedResponse(1, null, orderSetDTOList);
    }

    /**
     * 检查组合单号是否都存在
     *
     * @param inputOrderNoList 组合单号列表
     */
    private CheckOrderNoIsExistRecord checkOrderNoIsExist(List<String> inputOrderNoList) {
        LambdaQueryWrapper<OrderEntity> queryWrapper = new LambdaQueryWrapper<OrderEntity>()
                .select(OrderEntity::getOrderNo)
                .in(OrderEntity::getOrderNo, inputOrderNoList);
        List<String> orderNoInDatabaseList = orderMapper.selectList(queryWrapper).stream().map(OrderEntity::getOrderNo).toList();
        boolean allExist = new HashSet<>(orderNoInDatabaseList).containsAll(new HashSet<>(inputOrderNoList));
        return new CheckOrderNoIsExistRecord(allExist, inputOrderNoList, orderNoInDatabaseList);
    }

    private record CheckOrderNoIsExistRecord(
            boolean allIsExist, List<String> inputOrderNoList, List<String> databaseOrderNoList
    ) {}

    /**
     * 检查组合单号的配料对应的料仓和原料牌号是否以下发到对照表
     *
     * @param inputOrderNoList 组合单号列表
     */
    private CheckOrderNoSiloIsExistRecord checkOrderNoSiloIsExist(List<String> inputOrderNoList) {
        List<List<SelectSiloByOrderNoDTO>> selectSiloByOrderNoDTOListList = new ArrayList<>();
        for (String orderNo : inputOrderNoList) {
            List<String> recipeTableSiloList = recipeMapper.selectSilo(orderNo);
            List<SelectSiloByOrderNoDTO> selectSiloByOrderNoDTOList = siloRawMaterialMapMapper.selectSilo(orderNo);
            selectSiloByOrderNoDTOListList.add(selectSiloByOrderNoDTOList);
            List<String> mapTableSiloList = selectSiloByOrderNoDTOList.stream().map(SelectSiloByOrderNoDTO::getSilo).toList();
            if (!recipeTableSiloList.equals(mapTableSiloList)) {
                return new CheckOrderNoSiloIsExistRecord(false, orderNo, List.of(), recipeTableSiloList, mapTableSiloList);
            }
        }
        return new CheckOrderNoSiloIsExistRecord(true, "", selectSiloByOrderNoDTOListList, List.of(), List.of());
    }

    private record CheckOrderNoSiloIsExistRecord(
            boolean allIsExist, String orderNo, List<List<SelectSiloByOrderNoDTO>> selectSiloByOrderNoDTOList,
            List<String> recipeTableSiloList, List<String> mapTableSiloList
    ) {}

    private List<OrderSetDTO> buildOrderNoRecipe(List<List<SelectSiloByOrderNoDTO>> selectSiloByOrderNoDTOListList) {
        List<OrderSetDTO> result = new ArrayList<>();
        for (List<SelectSiloByOrderNoDTO> selectSiloByOrderNoDTOList : selectSiloByOrderNoDTOListList) {
            SelectSiloByOrderNoDTO selectSiloByOrderNoDTO = selectSiloByOrderNoDTOList.get(0);
            String machine = selectSiloByOrderNoDTO.getMachine();
            String screw = selectSiloByOrderNoDTO.getScrew();
            String orderNo = selectSiloByOrderNoDTO.getOrderNo();
            List<SiloSetDTO> siloSetDTOList = selectSiloByOrderNoDTOList.stream().map(dto ->
                    new SiloSetDTO(dto.getRawMaterialName(), dto.getSilo(), dto.getRatioAct())
            ).toList();
            result.add(new OrderSetDTO(orderNo, machine, screw, siloSetDTOList));
        }
        return result;
    }

    /**
     * 关闭组合单号
     *
     * @param orderNoList 组合单号列表
     */
    private void updateOrderNoIsClose(List<String> orderNoList) {
        LambdaUpdateWrapper<OrderEntity> updateWrapper = new LambdaUpdateWrapper<OrderEntity>()
                .set(OrderEntity::getIsClose, 1)
                .in(OrderEntity::getOrderNo, orderNoList);
        orderMapper.update(updateWrapper);
        log.info("组合单号: {}已关闭", orderNoList);
    }

}
